<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

require_once ('PrunusPlugin.php');

/**
 * PrunusSecurity
 * 
 * Plugin for security and users management 
 * 
 * @package Prunus   
 * @author agosto <agosto@7dedos.com>
 * @copyright	Copyright (c) 2009-2010, 7dedos
 * @link http://www.7dedos.com
 * @version 0.2
 * @access public
 */
class PrunusSecurity extends PrunusLibPlugin {
  private $usuId;
  private $usuName;
  private $usuRoles;
  private $pagId;
  
  /**
   * PrunusSecurity::__construct()
   * 
   * @return
   */
  public function __construct()	{
    parent::__construct();
    $this->version='0.2';
    $this->name='PrunusSecurity Plugin';
    $this->path = strtolower(@realpath(dirname(__FILE__)));
    $this->file = strtolower(@pathinfo(__FILE__, PATHINFO_BASENAME));
    
    $this->usuId = 0;
    $this->usuName = '';
    $this->usuRoles = array();
    $this->pagId = 0;
    
    $this->ci->load->model('PrunusSecurityModel');
    $this->ci->load->config('PrunusSecurity');
    $this->ci->load->database();
    $this->ci->load->helper('cookie');
    
    if (! ($this->usuId = $this->ci->session->userdata('usuId'))) { $this->usuId=0; };
    if ($this->logged) { //levanto de la base de datos la info del usuario
      $this->_getUserData($this->usuId,FALSE);
    } else { //usuario no logueado, intento levantar de la cookie local el idioma de preferencia
      $this->usuName = '';
      if (! $this->_isPublicZone()) redirect($this->ci->config->item('PRUNUSSEC_login_uri'), 'location', 301);
    }
  
    log_message('debug', 'PrunusSecurity inicializado');
  }
  
  /**
   * PrunusSecurity::__get()
   * 
   * Getter for class properties
   *    usuid - current user id (if there's no user logged returns 0')
   *    usuname - current user name
   *    usuroles - array of current user roles (key=id , value=name) 
   *    logged - boolean indicating if user is logged in
   * 
   * @param mixed $name property name
   * @return
   */
  public function __get($name) {
    switch (strtolower($name)) {
      case 'usuid':
        return ($this->usuId);
        break;
      case 'usuname':
        return ($this->usuName);
        break;
      case 'usuroles':
        return ($this->usuRoles);
        break;
      case 'logged':
        return ($this->usuId!=0);
        break;
      default:
        $trace = debug_backtrace();
        trigger_error(
            'Undefined property via __get(): ' . $name .
            ' in ' . $trace[0]['file'] .
            ' on line ' . $trace[0]['line'],
            E_USER_NOTICE);
        return null;
    }
  }
  
  /**
   * PrunusSecurity::__set()
   * 
   * Setter for class properties
   *    pagid - sets the current page by it's identifier 
   * 
   * 
   * @param mixed $name property name
   * @param mixed $value property value
   * @return
   */
  public function __set($name, $value) {
    switch (strtolower($name)) {
      case 'pagid': _setPageByIdentifier($value); break;
    }
  }
  
  /**
   * PrunusSecurity::__destruct()
   * 
   * @return
   */
  public function __destruct ()	{
    log_message('debug', 'PrunusSecurity destruida');
  }
  
  
  /**
   * PrunusSecurity::getLastUsername()
   * 
   * retrieves from cookie, the last succesfully logged in user
   * 
   * @return string user name
   */
  public function getLastUsername() { return (get_cookie($this->ci->config->item('PRUNUSSEC_cookie_last_user'), TRUE)); }


  /**
   * PrunusSecurity::login()
   * 
   * attempts to login the user
   * 
   * @param string $username user name
   * @param string $password user password (not hashed)
   * @return bool log in successful
   */
  public function login($username,$password) {
    $this->usuId = $this->_getUsuIdFromUsernameAndPassword ($username,$password);
    if ($this->usuId == 0) {
      $this->resultado = $this->msgLoginInvalido;
    } else {
      $this->_getUserData();
      if ($this->ci->config->item('PRUNUSSEC_cookie_last_user') !== null) set_cookie($this->ci->config->item('PRUNUSSEC_cookie_last_user'), $this->usuName, 86500); //grabo el valor en la cookie
    }
    $this->ci->session->set_userdata('usuId', $this->usuId);  
    return ($this->usuId!=0);
  }
  

  /**
   * PrunusSecurity::logout()
   * 
   * destroys user session 
   * 
   * @return void 
   */
  public function logout() {
    $this->ci->session->unset_userdata('usuId');
    $this->ci->session->sess_destroy();  
    $this->usuId = 0;
  }

  
  /**
   * PrunusSecurity::_getUsuIdFromUsernameAndPassword()
   * 
   * @param string $userName nombre del usuario
   * @param string $password password no hasheada
   * @return int if success, the user id, else zero
   */
  private function _getUsuIdFromUsernameAndPassword ($userName,$password) {
    $usu = $this->ci->PrunusSecurityModel->getUser(null, $userName, 1)->row();
    if (count($usu) !=1) {
      $usuId = 0;
    } else {
      if ($usu->usu_id != 0 ) {
        $hash = $usu->usu_pwdHash;
        if ($hash != '') {
          $salt_length = $this->ci->config->item('PRUNUSSEC_salt_length');
          $salt = substr($hash, 0, $salt_length);
          $password = $salt . substr(sha1($salt . $password), 0, -$salt_length);
          if ($hash !== $password) $usuId = 0;
        } else {
          $usuId = 0;
        }
      } else {
        $usuId = 0;
      }
    }
    return ($usu->usu_id);
  }
  





/* INTERFAZ PRIVADA *********************************************************************************************************/
  /**
   * PrunusSecurity::_salt()
   * 
   * @return string salt for md5 hashing
   */
  private function _salt() { return substr(md5(uniqid(rand(), true)), 0, $this->ci->config->item('PRUNUSSEC_salt_length')); }
  
  /**
   * PrunusSecurity::_isPublicZone()
   * 
   * @return bool if the current uri is a public zone
   */
  private function _isPublicZone() {
    switch (strtolower($this->ci->uri->segment(1,''))) {
      case "admin": 
        switch (strtolower($this->ci->uri->segment(2,''))) {
          //case "login": return(TRUE); 
          default: return(FALSE);
        }
      default: return(TRUE);
    }
  }
  
  /**
   * PrunusSecurity::_setPageByIdentifier()
   * 
   * sets the current page by it's identifier and also checks for permissions.
   * 
   * @param string $pagIdentifier page identifier
   * @return bool page setted succesfully (permissions ok)
   */
  private function _setPageByIdentifier ($pagIdentifier) {
    //busco la pagina y permisos
    //si esta todo ok, seteo el pagId, sino la dejo en cero
    $pag = $this->ci->PrunusSecurityModel->getPage(null, $pagIdentifier, 1);
    $rolesList = array();
    foreach($this->usuRoles as $k=>$v) $rolesList[] = $k;
    $permisos = $this->ci->PrunusSecurityModel->getUsuPermisosPage($this->usuId, $pag->pag_id, $rolesList)->row();
    $permisoFinal = null;
    if (count($permisos) > 0) {
      $permisoRol = null;
      if ($permisos->per_rol_neg > 0  && $permisos->per_rol_nul == 0 && $permisos->per_rol_pos == 0) $permisoRol = FALSE;
      if ($permisos->per_rol_neg == 0 && $permisos->per_rol_nul == 0 && $permisos->per_rol_pos > 0) $permisoRol = TRUE;
      if ($permisos->per_rol_neg != 0  || $permisos->per_rol_nul != 0 || $permisos->per_rol_pos != 0) $permisoRol = $this->ci->config->item('PRUNUSSEC_seguridad_colision_roles');
    
      $permisoUsu = null;
      if ($permisos->per_usu_neg > 0  && $permisos->per_usu_nul == 0 && $permisos->per_usu_pos == 0) $permisoUsu = FALSE;
      if ($permisos->per_usu_neg == 0 && $permisos->per_usu_nul == 0 && $permisos->per_usu_pos > 0) $permisoUsu = TRUE;
      if ($permisos->per_usu_neg != 0  || $permisos->per_usu_nul != 0 || $permisos->per_usu_pos != 0) $permisoUsu = $this->ci->config->item('PRUNUSSEC_seguridad_colision_roles');
      
      if ($permisoRol == null && $permisoUsu == null) {
        $permisoFinal = $this->ci->config->item('PRUNUSSEC_seguridad_colision_roles');
      } else {
        if ($permisoRol == null) $permisoFinal = $permisoUsu;
        if ($permisoUsu == null) $permisoFinal = $permisoRol;
        if ($permisoUsu == $permisoRol) $permisoFinal = $permisoRol;
        if ($permisoFinal == null) {
          if ($this->ci->config->item('PRUNUSSEC_seguridad_colision_roles')) $permisoFinal = $permisoUsu; else $permisoFinal = $permisoRol;
        }
      }
    }
    
    if ($permisoFinal == null) $permisoFinal = $this->ci->config->item('PRUNUSSEC_seguridad_colision_roles');

    
    //fin de la evaluacion
    if ($permisoFinal) {
      $this->pagId = $pagIdentifier; 
      return ( TRUE );
    } else {
      $this->pagId = 0; 
      return ( FALSE );
    }
  }

  /**
   * PrunusSecurity::_getUserData()
   * 
   * @param integer $usuId user id to get data (if zero, uses the current user logged in)
   * @return
   */
  private function _getUserData($usuId=0) {
    if ($usuId === 0) $usuId = $this->usuId;
    $data = $this->ci->PrunusSecurityModel->getUser($usuId, null, 1)->row();
    $this->usuName = $data->usu_name;
    $this->usuRoles = array();
    $roles = $this->ci->PrunusSecurityModel->getUsuRoles($usuId, null)->result();
    foreach ($roles as $rol) {
      $this->usuRoles[$rol->rol_id] = $rol->rol_name;
    }
  }
  
  /**
   * PrunusSecurity::_getMenuULHijos()
   * 
   * Recursive function to read and build menu tree
   * 
   * @param mixed $meiId
   * @param string $classCurrentLI
   * @param string $classLI
   * @return
   */
  private function _getMenuULHijos ($meiId, $classCurrentLI = '', $classLI = '') {
    //busco meiId - lo agrego al string - llamo recursivamente hijos
    $item = $this->menuArray[$meiId];
    
    if ($meiId != $this->currentMenuItem) {
      if ($classLI != '') $class = " class=\"". $classLI . "\""; else $class='';
      $out = "<li><span" . $class . ">" . anchor($this->menuArray[$meiId]["uri"],$this->menuArray[$meiId]["name"]) . "</span>";
    } else {
      if ($classCurrentLI !== '') $class = " class=\"". $classCurrentLI . "\""; else $class=" class=\"". $classLI . "\"";
      $out = "<li><span" . $class . ">" . anchor($this->menuArray[$meiId]["uri"],$this->menuArray[$meiId]["name"]) . "</span>";
    }
    
    if (count($this->menuArray[$meiId]["children"])>0) $out .= "<ul>";
    foreach ($this->menuArray[$meiId]["children"] as $child) {
      $out .= $this->_getMenuULHijos($child, $classCurrentLI, $classLI);
    }
    if (count($this->menuArray[$meiId]["children"])>0) $out .= "</ul>";
    $out .= "</li>";
    return ($out);
  }

  /**
   * PrunusSecurity::_buildMenuHijos()
   * 
   * @param mixed $res
   * @param mixed $menu
   * @param mixed $meiId
   * @return
   */
  private function _buildMenuHijos (&$res,&$menu,$meiId) {
    //busco los hijos. los agrego como hijos de meiId y llamo recursivamente hasta q no tenga mas hijos
    //busco hijos
    foreach($res as $row) {
      if ($row->mei_mei == $meiId) {
        $menu[$meiId]["children"][] = $row->mei_id;
        $menu[$row->mei_id] = array("parent"=>$meiId, "uri"=>$row->mei_uri, "name"=>$this->getMenuItemName($row->mei_id), "children"=>array());
        $this->_buildMenuHijos($res, $menu, $row->mei_id);
      }
    }
  }
/********************************************************************************************************* INTERFAZ PRIVADA */

  
  
}